package org.eclipse.php.internal.console.ui.editor;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.InvocationTargetException;

import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IWorkspaceRoot;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import org.eclipse.debug.core.DebugException;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.debug.core.model.IThread;
import org.eclipse.jface.operation.IRunnableWithProgress;
import org.eclipse.php.debug.core.debugger.parameters.IDebugParametersInitializer;
import org.eclipse.php.debug.core.debugger.parameters.IDebugParametersKeys;
import org.eclipse.php.internal.console.ui.util.Util;
import org.eclipse.php.internal.debug.core.IPHPDebugConstants;
import org.eclipse.php.internal.debug.core.Logger;
import org.eclipse.php.internal.debug.core.PHPDebugCoreMessages;
import org.eclipse.php.internal.debug.core.PHPDebugPlugin;
import org.eclipse.php.internal.debug.core.launching.DebugSessionIdGenerator;
import org.eclipse.php.internal.debug.core.launching.PHPLaunch;
import org.eclipse.php.internal.debug.core.launching.PHPLaunchUtilities;
import org.eclipse.php.internal.debug.core.phpIni.PHPINIUtil;
import org.eclipse.php.internal.debug.core.preferences.PHPProjectPreferences;
import org.eclipse.php.internal.debug.core.preferences.PHPexeItem;
import org.eclipse.php.internal.debug.core.preferences.PHPexes;
import org.eclipse.php.internal.debug.core.zend.communication.DebuggerCommunicationDaemon;
import org.eclipse.php.internal.debug.core.zend.debugger.DebugParametersInitializersRegistry;
import org.eclipse.php.internal.debug.core.zend.debugger.DefaultExpressionsManager;
import org.eclipse.php.internal.debug.core.zend.debugger.Expression;
import org.eclipse.php.internal.debug.core.zend.debugger.PHPSessionLaunchMapper;
import org.eclipse.php.internal.debug.core.zend.model.PHPDebugTarget;


public class MyRunnable implements IRunnableWithProgress {
	
	private static final String PHP_DEADLOOP_FILE="deadloop.php";
	private static final String LINE_BREAK=System.getProperty("line.separator");
	private static final String PHP_DEADLOOP_FILE_CONTENT="<?php" + LINE_BREAK
			+ "while(true){" + LINE_BREAK + "echo(\"\");" + LINE_BREAK + "}";
	private IProject project;
	private String in;
	private String mesg;
	private String result;
	private IFile file;
	public String getResult() {
		return result;
	}

	public MyRunnable(String in,IProject project, IFile file) {
		this.in=in;
		this.project=project;
		this.file=file;
	}

	public String getMesg() {
		return mesg;
	}

	public void run(IProgressMonitor monitor)
			throws InvocationTargetException, InterruptedException {
		monitor.beginTask("Computing", 100);
		// PHPDebugTarget debugTarget = null;
		// IAdaptable adaptable = debugTarget;
		// if(adaptable instanceof PHPThread){
		// debugTarget = (PHPDebugTarget) ((PHPThread)adaptable)
		// .getDebugTarget();
		// }
		PHPDebugTarget debugTarget=null;
		if (launch == null) {
			startTarget();
		}
		int i=0;
		if (!init) {
			while (i++ < 100 && debugTarget == null) {
				Thread.sleep(2000);
				debugTarget=(PHPDebugTarget) launch.getDebugTarget();
			}
		} else {
			debugTarget=(PHPDebugTarget) launch.getDebugTarget();
		}

		// if (adaptable instanceof PHPStackFrame) {
		// PHPStackFrame stackFrame = (PHPStackFrame) adaptable;
		// debugTarget = (PHPDebugTarget) stackFrame
		// .getDebugTarget();
		// result = getValue(debugTarget, in);
		// try {
		// //refresh the variable view
		// debugTarget.stepOver();
		// } catch (DebugException e) {
		// // TODO Auto-generated catch block
		// e.printStackTrace();
		// }
		// }else{
		// mesg = "there is no DebugTarget";
		// }

		if (debugTarget != null) {
			if (in.trim().startsWith("exit")) {
				stopTarget(debugTarget);
				mesg="exit";
				return;
			}
			result=getValue(debugTarget, in);
			try {
				// must be called to trigger later refresh
				// or contextActivated#contextActivated will never be
				// called.
				// if(!init){
				// MemoryView.contextActivated(debugTarget);
				// IThread[] threads=debugTarget.getThreads();
				// for (int j=0; j < threads.length; j++) {
				// MemoryView.contextActivated(threads[j]);
				// IStackFrame sf=threads[j].getTopStackFrame();
				// if (sf != null)
				// MemoryView.contextActivated(sf);
				// }
				//						
				// }
				IThread[] threads=debugTarget.getThreads();
				if(threads != null && threads.length > 0){
					threads[0].stepOver();
				}
//				debugTarget.stepOver();
				// IOperationHistory history =
				// PlatformUI.getWorkbench().getOperationSupport().getOperationHistory();
				// refresh the variable view

			} catch (DebugException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		} else {
			mesg="there is no DebugTarget";
		}
		if (debugTarget != null) {
			init=true;
		}
		monitor.done();
	}

	private void startTarget() {
		String fileNameString="deadloop.php";
		final IWorkspaceRoot workspaceRoot=ResourcesPlugin
				.getWorkspace().getRoot();
		final IPath filePath=new Path(fileNameString);
		IResource res=workspaceRoot.findMember(filePath);
		ILaunchConfiguration configuration=new MyLaunchConfiguration();
		PHPexeItem defaultItem=PHPexes.getInstance().getDefaultItem(
				DebuggerCommunicationDaemon.ZEND_DEBUGGER_ID);
		if (defaultItem == null) {
			// We have no executable defined for this debugger.
			mesg="please config zend debug first!";
			return;
		}
		String phpExeString=defaultItem.getExecutable()
				.getAbsolutePath();
		// String phpExeString =
		// "C:\\Program Files\\Zend\\ZendServer\\bin\\php.exe";
		try {
			configuration.getAttributes().put(
					IPHPDebugConstants.ATTR_FILE, fileNameString);
			configuration.getAttributes().put(
					IDebugParametersKeys.TRANSFER_ENCODING,
					PHPProjectPreferences.getTransferEncoding(project));
			configuration.getAttributes().put(
					IDebugParametersKeys.OUTPUT_ENCODING,
					PHPProjectPreferences.getOutputEncoding(project));
			configuration.getAttributes().put(
					IPHPDebugConstants.ATTR_EXECUTABLE_LOCATION,
					phpExeString);
			configuration.getAttributes().put(
					IPHPDebugConstants.RUN_WITH_DEBUG_INFO, true);
		} catch (CoreException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

		launch=new PHPLaunch(configuration, ILaunchManager.DEBUG_MODE,
				null);

		File phpIni=defaultItem.getINILocation();
		if (phpIni == null || !phpIni.exists())
			phpIni=PHPINIUtil.findPHPIni(phpExeString);
		File tempIni=PHPINIUtil.prepareBeforeDebug(phpIni,
				phpExeString, project);
		String port=Integer
				.toString(PHPDebugPlugin
						.getDebugPort(DebuggerCommunicationDaemon.ZEND_DEBUGGER_ID));
		// copy from PHPExecutableLaunchDelegate
		launch.setAttribute(IDebugParametersKeys.PHP_INI_LOCATION,
				tempIni.getAbsolutePath());
		launch.setAttribute(IDebugParametersKeys.PORT, port);
		launch.setAttribute("org.eclipse.debug.core.capture_output",
				null);
		launch.setAttribute(IDebugParametersKeys.FIRST_LINE_BREAKPOINT,
				"true");
		launch.setAttribute(IDebugParametersKeys.EXECUTABLE_LAUNCH,
				"true");
		launch.setAttribute(
				"org.eclipse.debug.ui.ATTR_CONSOLE_ENCODING", "UTF-8");
		launch.setAttribute(IPHPDebugConstants.DEBUGGING_PAGES,
				IPHPDebugConstants.DEBUGGING_ALL_PAGES);

		int sessionID=DebugSessionIdGenerator.generateSessionID();
		PHPSessionLaunchMapper.put(sessionID, launch);
		launch.setAttribute(IDebugParametersKeys.SESSION_ID, Integer
				.toString(sessionID));
		File phpDeadloopFile=createTemporaryPHPDeadloopFile(file);
		try {
			debugPHPExecutable(launch, phpExeString, phpDeadloopFile
					.getAbsolutePath());
//			phpDeadloopFile.deleteOnExit();
//			file.getParent().refreshLocal(1, new NullProgressMonitor());
		} catch (DebugException e) {
			mesg="there is no DebugTarget";
		} 
//		catch (CoreException e) {
//			e.printStackTrace();
//		}
	}

	private void stopTarget(PHPDebugTarget debugTarget) {
		try {
			debugTarget.terminate();
		} catch (DebugException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		debugTarget=null;
		launch=null;
		init=false;
	}

	/**
	 * Returns the variable value.
	 * 
	 * @param variable
	 *            The variable name
	 * @return
	 */
	protected String getValue(PHPDebugTarget debugTarget, String variable) {
		DefaultExpressionsManager expressionManager=debugTarget
				.getExpressionManager();
		if (expressionManager == null) {
			stopTarget(debugTarget);
			return "initializing...please try later";
		}

		Expression expression=expressionManager.buildExpression(variable);

		// Get the value from the debugger
		debugTarget.getExpressionManager().getExpressionValue(expression, 1);
		expressionManager.update(expression, 1);
		String value=expression.getValue().getValueAsString();

		if (value != null && value.length() == 0) {
			value="Empty";
			return value;
		}

		if (value != null) {
			value.replaceAll("\t", "    ");
		}

		return value;
	}

	private static boolean init=false;
	// static PHPDebugTarget debugTarget = null;
	public static ILaunch launch;

	public static void debugPHPExecutable(ILaunch launch, String phpExe,
			String fileToDebug) throws DebugException {
		try {
			launch.setAttribute(IDebugParametersKeys.EXECUTABLE_LAUNCH, Boolean
					.toString(true));

			IDebugParametersInitializer parametersInitializer=DebugParametersInitializersRegistry
					.getBestMatchDebugParametersInitializer(launch);
			PHPExecutableDebuggerInitializer debuggerInitializer=new PHPExecutableDebuggerInitializer(
					launch);

			String phpExeString=new File(phpExe).getAbsolutePath();
//			String fileName=new File(fileToDebug).getAbsolutePath();
			String query=PHPLaunchUtilities.generateQuery(launch,
					parametersInitializer);
			// query = query + "&debug_start_session=1";
			String iniFileLocation=launch
					.getAttribute(IDebugParametersKeys.PHP_INI_LOCATION);
			String workingDir=new File(fileToDebug).getParentFile()
					.getAbsolutePath();

			debuggerInitializer.initializeDebug(phpExeString, fileToDebug,
					workingDir, query, null, iniFileLocation);

		} catch (java.io.IOException e1) {
			Logger.logException(
					"PHPDebugTarget: Debugger didn't find file to debug.", e1);
			String errorMessage=PHPDebugCoreMessages.DebuggerFileNotFound_1;
			throw new DebugException(new Status(IStatus.ERROR, PHPDebugPlugin
					.getID(), IPHPDebugConstants.INTERNAL_ERROR, errorMessage,
					e1));
		}
	}

	/**
	 * Creates temporary PHP configuration file and returns its instance of
	 * <code>null</code> in case of error. This file will be removed when the
	 * program exits.
	 * @param file 
	 * 
	 * @param originalPHPIniFile
	 *            If specified - its contents will be copied to the temporary
	 *            file
	 * @return temporary PHP configuration file instance
	 */
	public static File createTemporaryPHPDeadloopFile(IFile file) {
		
		File phpDeadloopFile=null;
		try {
			if(file != null){
				IContainer container = file.getParent();
				final IFile deadloopFile = container.getFile(new Path(PHP_DEADLOOP_FILE));
				Util.setFileContent(deadloopFile,PHP_DEADLOOP_FILE_CONTENT,new NullProgressMonitor());
				phpDeadloopFile=deadloopFile.getLocation().toFile();
			}else{
				// Create temporary directory:
				File tempDir=new File(
						System.getProperty("java.io.tmpdir"), "zend_debug"); //$NON-NLS-1$ //$NON-NLS-2$
				if (!tempDir.exists()) {
					tempDir.mkdir();
					tempDir.deleteOnExit();
				}
				tempDir=File.createTempFile("session", null, tempDir); //$NON-NLS-1$
				tempDir.delete(); // delete temp file
				tempDir.mkdir();
				tempDir.deleteOnExit();

				phpDeadloopFile=new File(tempDir, PHP_DEADLOOP_FILE);
				phpDeadloopFile.createNewFile();
				phpDeadloopFile.deleteOnExit();

				BufferedWriter bos=new BufferedWriter(new FileWriter(
						phpDeadloopFile));
				bos.write(PHP_DEADLOOP_FILE_CONTENT);
				bos.close();
			}
		} catch (Exception e) {
			PHPDebugPlugin.log(e);
		}
		return phpDeadloopFile;
	}

}

